﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using static System.Net.Mime.MediaTypeNames;

namespace pdfer.Syntax
{
    [Obsolete("建议使用 PSCompilationEngineV2")]
    internal class PSCompilationEngine
    {
        private static List<String> symbolTable1
            = new() { "<<", "[", ">>", "]" , "%" };

        //private static List<String> symbolTable2
        //    = new() {  ">>", "]" };

        private static List<String> keywordTable =
            [
                "R", "false", "true", "null"
            ];

        /// <summary>
        /// 字符
        /// </summary>
        private static Regex RegWD = new(@"\w");
        private List<PSToken> result = new();
        public List<PSToken> GetPSTokens(String? ps, Byte[] psBin)
        {
            ArgumentException.ThrowIfNullOrWhiteSpace(ps);
            var psSpan = psBin.AsSpan();
            var wds = ps.AsSpan();
            StringBuilder token = new();
            for (var i = 0; i < wds.Length; i++)
            {
                var wd = wds[i];
                if (RegWD.IsMatch(wd.ToString()))
                {
                    token.Append(wd);
                }
                else if(wd == '/')
                {
                    if (token.Length > 0)
                    {
                        NewToken(i - token.Length, token.ToString());
                        token = new();
                    }
                    token.Append(wd);
                }
                else if(wd == '\\')
                {
                    // 转义的情况
                    token.Append(wds[i+1]);
                    i++;
                }
                else if(wd == '<') 
                {
                    if (token.Length > 0)
                    {
                        NewToken(i - token.Length, token.ToString());
                        token = new();
                    }
                    if (wds[i + 1] == '<')
                    {
                        // 字典
                        i++;
                        token.Append('<');
                        token.Append('<');
                        NewToken(i - token.Length, token.ToString());
                        token = new();
                        // 配对 >>
                    }
                    else
                    {
                        token.Append(wd);
                        // 字符串
                        // 直到 >
                        while (true)
                        {
                            i++;
                            if(i >= wds.Length)
                            {
                                // 字符串截断 报错
                                throw new Exception("未结束的字符串");
                            }
                            wd = wds[i];
                            token.Append(wd);
                            if(wd == '>')
                            {
                                break;
                            }
                        }
                        NewToken(i - token.Length, token.ToString());
                        token = new();
                    }
                }
                else if(wd == '>')
                {
                    if (wds[i + 1] == '>')
                    {
                        // 字典结束符号
                        if (token.Length > 0)
                        {
                            NewToken(i - token.Length, token.ToString());
                            token = new();
                        }
                        i++;
                        token.Append('>');
                        token.Append('>');
                        NewToken(i - token.Length, token.ToString());
                        token = new();
                    }
                    else
                    {
                        throw new Exception("期待>> 实际 >");
                    }
                }
                else if (wd == '(')
                {
                    if (token.Length > 0)
                    {
                        NewToken(i - token.Length, token.ToString());
                        token = new();
                    }
                    token.Append(wd);
                    // 字符串
                    // 直到 )
                    var leftP = 0;
                    var baseIdx = i + 1;
                    while (true)
                    {
                        i++;
                        if (i >= wds.Length)
                        {
                            // 字符串截断 报错
                            throw new Exception("未结束的字符串");
                        }
                        wd = wds[i];
                        token.Append(wd);
                        if(wd == '(')
                        {
                            leftP++;
                        }
                        else if (wd == ')')
                        {
                            leftP--;
                            if(leftP < 0)
                            {
                                break;
                            }
                        }
                    }
                    if (token.Length > 4 && (psBin[baseIdx] + psBin[baseIdx + 1]) == 0xFE + 0xFF)
                    {
                        var codingCode = psBin[baseIdx] == 0xFE ? 1201 : 1200;
                        // Unicode字节顺序标记U + FEFF，表示UTF16BE编码
                        // Unicode字节顺序标记U + FFFE，表示UTF16LE编码
                        var by = psSpan.Slice(baseIdx , token.Length - 2);
                        if (by.IndexOf((Byte)'\\') > -1)
                        {
                            var by2 = new Byte[by.Length];
                            var curr = 0;
                            for(var _idx = 0; _idx < by.Length ; _idx++)
                            {
                                if (by[_idx] == (Byte)'\\')
                                {
                                    // 查看下一个
                                    var next = by[_idx + 1];
                                    _idx++;
                                    switch (next)
                                    {
                                        case 98:  // 0x62 b \b
                                            next = 8;
                                            break;
                                        case 102: // 0x66 f \f
                                            next = 12;
                                            break;
                                        case 110: // 0x6e n \n
                                            next = 10;
                                            break;
                                        case 114: // 0x72 r \r
                                            next = 13;
                                            break;
                                        case 116: // 0x74 t \t
                                            next = 9;
                                            break;
                                        case 10:
                                            continue;
                                        case 13:
                                            next = by[_idx + 1];
                                            if(next == 10)
                                            {
                                                //移动_idx
                                                // 忽略 \r
                                                _idx++;
                                            }
                                            continue;
                                        default:
                                            {
                                                var c = 0;
                                                var _ = 0;
                                                do
                                                {
                                                    next = by[_idx];
                                                    if (next < 48 || next > 55)
                                                    {
                                                        break;
                                                    }
                                                    _idx++;
                                                    _ = (_ << 3) + next - 48;
                                                    c++;
                                                }
                                                while (c < 3);
                                                if(c > 2)
                                                {
                                                    next = (Byte)(_ & 0xff);
                                                }
                                                break;
                                            }
                                    }
                                    by2[curr++]=next;
                                }
                                else
                                {
                                    by2[curr++] = by[_idx];
                                }
                            }
                            var ss = Encoding.GetEncoding(codingCode).GetString(by2.AsSpan(0, curr));
                            NewToken(i - token.Length, $"({ss})");
                        }
                        else
                        {
                            var ss = Encoding.GetEncoding(codingCode).GetString(by);
                            NewToken(i - token.Length, $"({ss})");
                        }
                    }
                    else
                    {
                        // PDFDocEncoding
                        // 暂未发现问题
                        NewToken(i - token.Length, token.ToString());
                    }
                    token = new();
                }
                else if (wd == '\n' || wd == ' ')
                {
                    if (token.Length > 0)
                    {
                        NewToken(i - token.Length, token.ToString());
                        token = new();
                    }
                }
                else if(wd == '[' || wd == ']')
                {
                    if (token.Length > 0)
                    {
                        NewToken(i - token.Length, token.ToString());
                        token = new();
                    }
                    token.Append(wd);
                    NewToken(i - token.Length, token.ToString());
                    token = new();
                }
            }
            return result;
        }

        /// <summary>
        /// 创建一个新的token
        /// </summary>
        /// <param name="v1"></param>
        /// <param name="v2"></param>
        /// <exception cref="NotImplementedException"></exception>
        private void NewToken(Int32 index, String v)
        {
            result.Add(new PSToken
            {
                Index = index,
                Length = v.Length,
                Token = v,
                Type = GetTokenType(v)
            });
        }

        private TokenType GetTokenType(String token)
        {
            if (String.IsNullOrEmpty(token))
            {
                return TokenType.None;
            }
            if (symbolTable1.Any(p => p == token.ToLower()))
            {
                return TokenType.SYMBOLOpen;
            }
            //if (symbolTable2.Any(p => p == token.ToLower()))
            //{
            //    return TokenType.SYMBOLClose;
            //}
            if (keywordTable.Any(p => p == token))
            {
                return TokenType.KEYWORD;
            }
            if (token.StartsWith('<') && token.EndsWith('>'))
            {
                return TokenType.STRING_HEX_CONST;
            }
            if (token.StartsWith('(') && token.EndsWith(')'))
            {
                return TokenType.STRING_CONST;
            }
            if (token.StartsWith('/'))
            {
                return TokenType.IDENTIFIER;
            }
            if (token.IndexOf('.') > -1)
            {
                if (Double.TryParse(token, out _))
                {
                    return TokenType.NUMBER_CONST;
                }
            }
            if (Int32.TryParse(token, out _))
            {
                return TokenType.INT_CONST;
            }
            throw new NotSupportedException($"未知的Token类型： {token}");
        }

        internal Dictionary<String, Object> ParseToDictionary(List<PSToken> tokens)
        {
            Int32 i = 0;
            if (tokens[i].Token == "<<")
            {
                i++;
                var dic = InnerParseDic(tokens, ref i);
                return dic;
            }
            else
            {
                return [];
            }
        }

        internal List<Object> ParseToList(List<PSToken> tokens)
        {
            Int32 i = 0;
            if (tokens[i].Token == "[")
            {
                i++;
                var dic = InnerParseArr(tokens, ref i);
                return dic;
            }
            else
            {
                return [];
            }
        }

        private Dictionary<String, Object> InnerParseDic(List<PSToken> tokens, ref int i)
        {
            var result = new Dictionary<String, Object>();
            String? key = null;
            List<Object> val = [];
            Boolean getKey = true;
            for(;i < tokens.Count; i++)
            {
                var token = tokens[i];
                if(token.Type == TokenType.IDENTIFIER)
                {
                    if (getKey)
                    {
                        key = token.Token;
                        getKey = false;
                        // val -> Dic Arr 普通的值
                    }
                    else
                    {
                        if(val.Count > 0)
                        {
                            result.Add(key, val[0]);
                            i--;
                            getKey = true;
                            key = null;
                            val = [];
                        }
                        else
                        {
                            val.Add(token.Token);
                        }
                    }
                }
                else if (token.Token == "[")
                {
                    i++;
                    //val.AddRange(InnerParseArr(tokens, ref i));
                    //result.Add(key, val);
                    result.Add(key, InnerParseArr(tokens, ref i));
                    getKey = true;
                    key = null;
                    val = [];
                }
                else if (token.Token == "<<")
                {
                    i++;
                    //val.Add(InnerParseDic(tokens, ref i));
                    //result.Add(key, val);
                    result.Add(key, InnerParseDic(tokens, ref i));
                    getKey = true;
                    key = null;
                    val = [];
                }
                else if(token.Token == ">>")
                {
                    if (!getKey)
                    {
                        result.Add(key, String.Join(' ', val));
                    }
                    break;
                }
                else
                {
                    val.Add(token.Token);
                    if(token.Token == "R")
                    {
                        // 间接引用
                        if(val.Count == 3)
                        {
                            result.Add(key, String.Join(' ' ,val));
                        }
                        else if (val.Count > 3)
                        {
                            // 这里应该直接报错
                            result.Add(key, new object[] { val.Slice(0, val.Count - 3), String.Join(' ', val[^3]) });
                        }
                        else
                        {
                            // 这里应该直接报错
                            result.Add(key, val);
                        }
                        getKey = true;
                        key = null;
                        val = [];
                    }
                }
            }
            return result;
        }

        private List<Object> InnerParseArr(List<PSToken> tokens, ref int i)
        {
            var result = new List<Object>();
            for (; i < tokens.Count; i++)
            {
                var token = tokens[i];
                if(token.Token == "<<")
                {
                    i++;
                    result.Add(InnerParseDic(tokens, ref i));
                }
                else if (token.Token == "[")
                {
                    i++;
                    result.AddRange(InnerParseArr(tokens, ref i));
                }
                else if(token.Token == "]")
                {
                    break;
                }
                else
                {
                    if (token.Token == "R")
                    {
                        var v1 = result[^1];
                        var v2 = result[^2];
                        result.RemoveRange(result.Count - 2, 2);
                        result.Add($"{v2} {v1} {token.Token}");
                    }
                    else
                    {
                        result.Add(token.Token);
                    }
                }
            }
            return result;
        }


    }
}
